#ifndef Algebra_sgEigen_h
#define Algebra_sgEigen_h

#include "AlgebraModule.h"
#include "LinearSolver.h"

SG_NAMESPACE_OPEN

namespace Algebra
{
    /**
     * @brief Wrap Eigen's direct sparse LLT Cholesky factorizations.
     *
     * In Eigen's Sparse Linear Systems, the matrix will be generally factorized: LLT for self-adjoint matrices,
     * LDLT for general hermitianv matrices, LU for non hermitian matrices and QR for rectangular matrices.
     *
     * @see https://eigen.tuxfamily.org/dox/group__TopicSparseSystems.html
     *
     * LL^T and LDL^T Cholesky factorizations of sparse matrices that are selfadjoint and positive definite.
     * These factorizations allow for solving A.X = B where X and B can be either dense or sparse.
     *
     * @see https://eigen.tuxfamily.org/dox/classEigen_1_1SimplicialLLT.html
     *
     * @author nene
     * @date Augst, 2024.
     */
    // Extend for the complex data type
    template <typename TDataType>
    struct TEigenLLTPrivate;

    template <typename TDataType>
    class ALGEBRA_EXPORT TEigenLLT : public TLinearSolver<TDataType>
    {
      public:
        ///@name Type Definitions
        ///@{
        typedef /*typename*/ TDataType                 DataType;
        typedef /*typename*/ Vector_t<TDataType>       VectorType;
        typedef /*typename*/ Matrix_t<TDataType>       MatrixType;
        typedef /*typename*/ SparseMatrix_t<TDataType> SparseMatrixType;
        ///@}

        TEigenLLT ();
        ~TEigenLLT () override;

        const char* getClassName () override;

        /// perform a numeric factorization of the given sparse matrix.
        void compute (const SparseMatrixType& matrix) override;

        /// evaluate the solution x of Ax=b using the current decomposition of A.
        void solve (const VectorType& b, VectorType& x) const override;

        /// Computes the inverse of square matrix `b` (must be invertible) and stores it in `x` using direct solvers
        void solve (const SparseMatrixType& b, SparseMatrixType& x) const override;

        /// report whether previous computation was successful.
        Info_t info () const override;

      private:
        /// take Adapter Pattern to hide the underlying details.
        struct TEigenLLTPrivate<DataType>* d = nullptr;
    };

    // // alias for compatibilities with the external modules
    // typedef TEigenLLT<double> sgEigenLLT;
}  // namespace Algebra

SG_NAMESPACE_CLOSE

#endif  // Algebra_sgEigen_h